package com.didispace.hystrixCollapser;

import com.google.common.collect.Lists;
import com.netflix.hystrix.*;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

// p169 第二步， 通过继承 HystrixCollapser 实现请求合并器
/** p167
 *  @param BatchReturnType  合并后批量请求的返回类型
 *  @param ResponseType  单个请求返回的类型
 *  @param RequestArgumentType  单个请求返回的类型
 */
// public abstract class HystrixCollapser<BatchReturnType, ResponseType, RequestArgumentType> implements HystrixExecutable<ResponseType>, HystrixObservable<ResponseType> {
public class UserCollapseCommand extends HystrixCollapser<List<User>, User, Long> {

    private UserService userService;
    private Long userId;

    public UserCollapseCommand(UserService userService, Long userId) {
        super(Setter.withCollapserKey(HystrixCollapserKey.Factory.asKey("UserCollapseCommand")).andCollapserPropertiesDefaults(
                // 为请求合并器设置了时间延迟属性，合并器会在该时间窗内收集获取单个 User 的请求并在时间窗结束时进行合并组装成单个批量请求
                HystrixCollapserProperties.Setter().withTimerDelayInMilliseconds(100)));
        this.userService = userService;
        this.userId = userId;
    }

    // RequestArgumentType getRequestArgument() 用来定义获取请求参数的方法  p167  返回给定的单个请求参数 userId  p170
    @Override
    public Long getRequestArgument() {
        return userId;
    }

    // HystrixCommand<BatchReturnType> createCommand(Collection<HystrixCollapser.CollapsedRequest<ResponseType, RequestArgumentType>> var1)
    // 合并请求产生批量命令的具体实现方法  p167
    // p170  该方法的 collapsedRequests 参数中保存了延迟时间窗中收集到的所有获取单个 User 的请求。
    // 通过获取这些请求的参数来组织上面我们准备的批量请求命令 UserBatchCommand 实例。
    @Override
    protected HystrixCommand<List<User>> createCommand(Collection<CollapsedRequest<User, Long>> collapsedRequests) {
        // List<Long> userIds = new ArrayList<>();
        // userIds.addAll(collapsedRequests.stream().map(CollapsedRequest::getArgument).collect(Collectors.toList()));

        List<Long> userIds = new ArrayList<>();
        for (CollapsedRequest<User, Long> request: collapsedRequests) {
            userIds.add(request.getArgument());
        }
        return new UserBatchCommand(userService, userIds);
    }

    // mapResponseToRequests(BatchReturnType var1, Collection<HystrixCollapser.CollapsedRequest<ResponseType, RequestArgumentType>> var2);
    // 批量命令结果返回后的处理，这里需要实现将批量结果拆分并传递给合并前的各个原子请求命令的逻辑  p167
    // p170  在批量请求命令 UserBatchCommand 实例被触发执行完成之后，该方法开始执行，
    // 其中 batchResponse 参数保存了 createCommand 中组织的批量请求命令的返回结果，而 collapsedRequests 参数则代表了每个被合并的请求。
    // 在这里我们通过遍历批量结果 batchResponse 对象，为 collapsedRequests 中每个合并前的单个请求设置返回结果，
    // 以此完成批量结果到单个请求结果的转换
    @Override
    protected void mapResponseToRequests(List<User> batchResponse, Collection<CollapsedRequest<User, Long>> collapsedRequests) {
        int count = 0;
        for (CollapsedRequest<User, Long> collapsedRequest : collapsedRequests) {
            User user = batchResponse.get(count++);
            collapsedRequest.setResponse(user);
        }
    }
}
